package com.sahyadri.web.util.service.adpater;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.sahyadri.web.bean.Category;
import com.sahyadri.web.bean.Events;
import com.sahyadri.web.bean.GalleryDetails;
import com.sahyadri.web.bean.Location;
import com.sahyadri.web.bean.Menu;
import com.sahyadri.web.bean.MenuEntry;
import com.sahyadri.web.bean.MenuSearchCriteria;
import com.sahyadri.web.bean.Offer;
import com.sahyadri.web.bean.Organization;
import com.sahyadri.web.bean.Review;
import com.sahyadri.web.bean.SearchResults;
import com.sahyadri.web.model.Expense;

@Service
public class JpaLocationService implements LocationService {

    private EntityManager entityManager;

    public EntityManager getEntityManager() {
        return entityManager;
    }

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

   	

	@Override
	@Transactional
	public Location getLocation(Long locationId) {
		return entityManager.find(Location.class, locationId);
	}

	@Override
	@Transactional
	public List<Location> getAllLocation() {
		 Query query = getEntityManager().createQuery("select l from Location l");
	     return query.getResultList();
	}

	@Override
	@Transactional
	public List<Location> getLocationsByOrg(Organization org) {
		Organization organization = entityManager.find(Organization.class, org.getId());
		Collection<Location> locations = organization.getLocations();
		return new ArrayList<Location>(locations);
	}

	@Override
	@Transactional
	public void deleteLocation(Long locationId) {
		Location location = getLocation(locationId);
        getEntityManager().remove(location);
		
	}

	@Override
	@Transactional
	public Location createLocation(Organization org, Location location) {
   		Organization organization = entityManager.find(Organization.class, org.getId());
   		organization.getLocations().add(location);
		entityManager.persist(location);
	    return location;
	}
	
	@Override
	@Transactional
	public void updateLocation(Organization org, Location location) {
		Organization organization = entityManager.find(Organization.class, org.getId());
		organization.getLocations().add(location);
		getEntityManager().merge(location);
		
	}

	@Override
	@Transactional
	public Menu createMenu(long locationId, Menu menu) {
		Location location = entityManager.find(Location.class, locationId);
		location.getMenus().add(menu);
		entityManager.persist(menu);
		return menu;
	}

	@Override
	@Transactional
	public void updateMenu(long locationId, Menu menu) {
		Location location = entityManager.find(Location.class, locationId);
		location.getMenus().add(menu);
		entityManager.merge(menu);
		
	}

	@Override
	@Transactional
	public List<Menu> getMenuList(long locationId) {
		Location location = entityManager.find(Location.class, locationId);
		Collection<Menu> menus = location.getMenus();
		return new ArrayList<Menu>(menus);
	}

	@Override
	@Transactional
	public Menu getMenu(long menuId) {
		return entityManager.find(Menu.class, menuId);
	}

	@Override
	@Transactional
	public Category createCategory(long locationId, Category category) {
		Location location = entityManager.find(Location.class, locationId);
		location.getCategories().add(category);
		entityManager.persist(category);
		return category;
	}

	@Override
	@Transactional
	public void updateCategory(long locationId, Category category) {
		Location location = entityManager.find(Location.class, locationId);
		location.getCategories().add(category);
		entityManager.merge(category);
		
	}

	@Override
	@Transactional
	public Category getCategory(long categoryId) {
		Category catgeory = entityManager.find(Category.class, categoryId);
		catgeory.getMenus();
		return catgeory;
	}

	@Override
	@Transactional
	public List<Category> getCategoryList(long locationId) {
		Location location = entityManager.find(Location.class, locationId);
		Collection<Category> categoryList = location.getCategories();
		return new ArrayList<Category>(categoryList);
	}

	@Override
	@Transactional
	public Review createReview(long locationId, Review review) {
		Location location = entityManager.find(Location.class, locationId);
		location.getReviews().add(review);
		entityManager.persist(review);
		return review;
	}

	@Override
	@Transactional
	public void updateReview(long locationId, Review review) {
		Location location = entityManager.find(Location.class, locationId);
		location.getReviews().add(review);
		entityManager.merge(review);
		
	}

	@Override
	@Transactional
	public List<Review> getReviewList(long locationId) {
		Location location = entityManager.find(Location.class, locationId);
		Collection<Review> reviewList = location.getReviews();
		return new ArrayList<Review>(reviewList);
	}

	@Override
	@Transactional
	public Review getReview(long reviewId) {
		return entityManager.find(Review.class, reviewId);
	}

	@Override
	@Transactional
	public SearchResults<MenuEntry> searchMenuList(MenuSearchCriteria criteria) {
		SearchResults<MenuEntry> results = new SearchResults<MenuEntry>();
		
		
		CriteriaBuilder builder = entityManager.getCriteriaBuilder();
	    CriteriaQuery<Menu> query = builder.createQuery(Menu.class);
	    Root<Menu> menu = query.from(Menu.class);
	    query.select(menu);
		
	    List<Predicate> predicateList = new ArrayList<Predicate>();
	    
	    Predicate searchQueryPredicate;
	 
	    searchQueryPredicate = builder.like(
	            builder.upper(menu.<String>get("name")), "%"+criteria.getSearchQuery().toUpperCase()+"%");
	        predicateList.add(searchQueryPredicate);
	 
	    
	 
	    Predicate[] predicates = new Predicate[predicateList.size()];
	    predicateList.toArray(predicates);
	    query.where(predicates);
	    List<Menu> menuList = entityManager.createQuery(query).getResultList();
		
		    
		if(menuList.size() > 0) {
			for(Menu menuItem: menuList) {
				results.getResultList().add(new MenuEntry(menuItem));	
			}
		}
		
			results.setTotalResultsFound(menuList.size());
		
		return results;
	}

	@Override
	@Transactional
	public List<Events> getEventList(long locationId) {
		Location location = entityManager.find(Location.class, locationId);
		Collection<Events> eventList = location.getEvents();
		return new ArrayList<Events>(eventList);
	}

	@Override
	@Transactional
	public Events getEvent(long eventId) {
		return entityManager.find(Events.class, eventId);
	}

	@Override
	@Transactional
	public Events createEvent(long locationId, Events event) {
		Location location = entityManager.find(Location.class, locationId);
		location.getEvents().add(event);
		entityManager.persist(event);
		return event;
	}

	@Override
	@Transactional
	public void updateEvent(long locationId, Events event) {
		Location location = entityManager.find(Location.class, locationId);
		location.getEvents().add(event);
		entityManager.merge(event);
		
	}

	@Override
	@Transactional
	public List<Offer> getOfferList(long locationId) {
		Location location = entityManager.find(Location.class, locationId);
		Collection<Offer> offerList = location.getOffers();
		return new ArrayList<Offer>(offerList);
	}

	@Override
	@Transactional
	public Offer getOffer(long offerId) {
		return entityManager.find(Offer.class, offerId);
	}

	@Override
	@Transactional
	public Offer createOffer(long locationId, Offer offer) {
		Location location = entityManager.find(Location.class, locationId);
		location.getOffers().add(offer);
		entityManager.persist(offer);
		return offer;
	}

	@Override
	@Transactional
	public void updateOffer(long locationId, Offer offer) {
		Location location = entityManager.find(Location.class, locationId);
		location.getOffers().add(offer);
		entityManager.merge(offer);
		
	}

	@Override
	@Transactional
	public Menu assignMenu(long categoryId, long menuId) {
		Category category = entityManager.find(Category.class, categoryId);
		Menu menu = entityManager.find(Menu.class, menuId);
		category.getMenus().add(menu);
		entityManager.merge(category);
		return menu;
	}

	@Override
	@Transactional
	public List<GalleryDetails> getGalleryList(long locationId) {
		/*Location location = entityManager.find(Location.class, locationId);
		Collection<GalleryDetails> galleryList = location.getGalleryDetails();
		return new ArrayList<GalleryDetails>(galleryList);*/
		
		Query query = entityManager.createQuery("select gd from Location l join l.galleryDetails gd " +
				"where l.id= :locationId " +
				"ORDER BY gd.displayOrder ASC");
		query.setParameter("locationId", locationId);
		
		return query.getResultList();
	}

	@Override
	@Transactional
	public GalleryDetails getGallery(long galleryId) {
		return entityManager.find(GalleryDetails.class, galleryId);
	}

	@Override
	@Transactional
	public GalleryDetails createGallery(long locationId, GalleryDetails gallery) {
		
		Location location = entityManager.find(Location.class, locationId);
		location.getGalleryDetails().add(gallery);
		entityManager.persist(gallery);
		return gallery;
	}

	@Override
	@Transactional
	public void updateGallery(long locationId, GalleryDetails gallery) {
		Location location = entityManager.find(Location.class, locationId);
		location.getGalleryDetails().add(gallery);
		entityManager.merge(gallery);
		
	}

	@Override
	@Transactional
	public void deleteGallery(long locationId, long galleryId) {
		Location location = entityManager.find(Location.class, locationId);
		GalleryDetails gallery = entityManager.find(GalleryDetails.class, galleryId);
		location.getGalleryDetails().remove(gallery);
		entityManager.remove(gallery);
		
	}

	@Override
	@Transactional
	public void deleteLocation(Organization org, long locationId) {
		Organization organization = entityManager.find(Organization.class, org.getId());
		Location location = entityManager.find(Location.class, locationId);
		organization.getLocations().remove(location);
		entityManager.remove(location);
		
	}

	@Override
	@Transactional
	public void deleteEvent(long locationId, long eventId) {
		Location location = entityManager.find(Location.class, locationId);
		Events event = entityManager.find(Events.class, eventId);
		location.getEvents().remove(event);
		entityManager.remove(event);
		
	}

	@Override
	@Transactional
	public void deleteOffer(long locationId, long offerId) {
		Location location = entityManager.find(Location.class, locationId);
		Offer offer = entityManager.find(Offer.class, offerId);
		location.getOffers().remove(offer);
		entityManager.remove(offer);
		
	}

	@Override
	@Transactional
	public void deleteMenu(long locationId, long menuId) {
		Location location = entityManager.find(Location.class, locationId);
		Menu menu = entityManager.find(Menu.class, menuId);
		location.getMenus().remove(menu);
		entityManager.remove(menu);
		
		
	}

	@Override
	@Transactional
	public void deleteCategory(long locationId, long categoryId) {
		Location location = entityManager.find(Location.class, locationId);
		Category category = entityManager.find(Category.class, categoryId);
		location.getCategories().remove(category);
		entityManager.remove(category);
		
	}

	@Override
	@Transactional
	public void deleteReview(long locationId, long reviewId) {
		Location location = entityManager.find(Location.class, locationId);
		Review review = entityManager.find(Review.class, reviewId);
		location.getReviews().remove(review);
		entityManager.remove(review);
		
	}

	@Override
	@Transactional
	public List<Review> getPublishedReviews(long locationId) {
		Query query = entityManager.createQuery("select r from Location l join l.reviews r " +
				"where l.id= :locationId and r.publish=:publish " +
				"ORDER BY r.reviewDate DESC");
		query.setParameter("locationId", locationId);
		query.setParameter("publish", true);
		return query.getResultList();
		
	}
}
